import java.util.*;

public class TokenUtils {
    //单例模式
    private static TokenUtils instance = new TokenUtils();

    private TokenUtils() {
        init();
    }

    public static TokenUtils getInstance() {
        return instance;
    }

    private String[] reservedWord = {"const", "void", "int", "if", "else", "while", "break", "continue", "return"};
    private List<Object> allText = new ArrayList<Object>();
    private Map<String, Object> identifiers = new HashMap<String, Object>();
    private Map<String, Object> constIdent = new HashMap<String, Object>();
    private Map<String, List<String>> funcIdent = new HashMap<String, List<String>>();
    private String[] symbols = {",", ";", "[", "]", "(", ")", "{", "}", "=", "+", "-", "!", "*", "/", "%", "<", ">", "<=", ">=", "==", "!=", "&&", "||", "++", "--"};
    private Map<String, String> printMap = new HashMap<String, String>();

    private int currentPosition = -1;

    private Map<String, List<String>> isPush = new HashMap<String, List<String>>();
    private Map<String, List<String>> isPop = new HashMap<String, List<String>>();
    private String[] inExp = {"(", ")", "+", "-", "*", "/", "%", "++", "--", "NNN", "!"};

    private Map<String, List<String>> isCondPush = new HashMap<String, List<String>>();
    private Map<String, List<String>> isCondPop = new HashMap<String, List<String>>();
    private String[] inCondExp = {"(", "++", "--", "NNN", "!", "||", "&&", "==", "!=", "<", ">", "<=", ">="};


    public void initPriority() {
        isPush.put("+", new ArrayList<String>(Arrays.asList("*", "/", "%", "(", "++", "--", "NNN", "!")));
        isPush.put("-", new ArrayList<String>(Arrays.asList("*", "/", "%", "(", "++", "--", "NNN", "!")));
        isPush.put("*", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));
        isPush.put("/", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));
        isPush.put("%", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));
        isPush.put("(", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", "(", ")", "++", "--", "NNN", "!")));
        isPush.put("++", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));
        isPush.put("--", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));
        isPush.put("!", new ArrayList<String>(Arrays.asList("(", "++", "--", "NNN", "!")));

        isPop.put("+", new ArrayList<String>(Arrays.asList("+", "-", ")")));
        isPop.put("-", new ArrayList<String>(Arrays.asList("+", "-", ")")));
        isPop.put("*", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("/", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("%", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put(")", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("++", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("--", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("!", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));
        isPop.put("NNN", new ArrayList<String>(Arrays.asList("+", "-", "*", "/", "%", ")")));

        isCondPush.put("||", new ArrayList<String>(Arrays.asList("&&", "==", "!=", "<", ">", "<=", ">=", "NNN")));
        isCondPush.put("&&", new ArrayList<String>(Arrays.asList("==", "!=", "<", ">", "<=", ">=", "NNN")));
        isCondPush.put("==", new ArrayList<String>(Arrays.asList("<", ">", "<=", ">=", "NNN")));
        isCondPush.put("!=", new ArrayList<String>(Arrays.asList("<", ">", "<=", ">=", "NNN")));
        isCondPush.put("<", new ArrayList<String>(Arrays.asList("NNN")));
        isCondPush.put(">", new ArrayList<String>(Arrays.asList("NNN")));
        isCondPush.put("<=", new ArrayList<String>(Arrays.asList("NNN")));
        isCondPush.put(">=", new ArrayList<String>(Arrays.asList("NNN")));

        isCondPop.put("||", new ArrayList<String>(Arrays.asList("||")));
        isCondPop.put("&&", new ArrayList<String>(Arrays.asList("||", "&&")));
        isCondPop.put("==", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=")));
        isCondPop.put("!=", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=")));
        isCondPop.put("<", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=", "<", ">", "<=", ">=")));
        isCondPop.put(">", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=", "<", ">", "<=", ">=")));
        isCondPop.put("<=", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=", "<", ">", "<=", ">=")));
        isCondPop.put(">=", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=", "<", ">", "<=", ">=")));
        isCondPop.put("NNN", new ArrayList<String>(Arrays.asList("||", "&&", "==", "!=", "<", ">", "<=", ">=")));
    }

    public void init() {
        printMap.put("int", "i32");
        printMap.put("return", "ret");

        funcIdent.put("getint", new ArrayList<String>(Arrays.asList("i32")));
        funcIdent.put("putint", new ArrayList<String>(Arrays.asList("void", "i32")));
        funcIdent.put("getch", new ArrayList<String>(Arrays.asList("i32")));
        funcIdent.put("putch", new ArrayList<String>(Arrays.asList("void", "i32")));
        funcIdent.put("getarray", new ArrayList<String>(Arrays.asList("i32", "i32*")));
        funcIdent.put("putarray", new ArrayList<String>(Arrays.asList("void", "i32", "i32*")));


        initPriority();
    }

    public Map<String, Object> getConstIdent() {
        return constIdent;
    }

    public Map<String, Object> getIdentifiers() {
        return identifiers;
    }

    public void setCurrentPosition(int currentPosition) {
        this.currentPosition = currentPosition;
    }

    public int getCurrentPosition() {
        return currentPosition;
    }

    public Map<String, List<String>> getIsCondPush() {
        return isCondPush;
    }

    public Map<String, List<String>> getIsCondPop() {
        return isCondPop;
    }

    public Map<String, List<String>> getIsPush() {
        return isPush;
    }

    public Map<String, List<String>> getIsPop() {
        return isPop;
    }

    public List<Object> getAllText() {
        return allText;
    }

    public String[] getSymbols() {
        return symbols;
    }

    public String getPrint(String key) {
        return printMap.get(key);
    }


    public Object getCurrent() {
        if (currentPosition >= allText.size()) {
            System.exit(3);
            return null;
        } else {
            return allText.get(currentPosition);
        }
    }

    public Object getBack() {
        if (currentPosition < 0) {
            System.exit(4);
            return null;
        } else {
            return allText.get(--currentPosition);
        }
    }

    public Object getNext() {
        if (currentPosition >= allText.size()) {
            System.exit(5);
            return null;
        } else {
            return allText.get(++currentPosition);
        }
    }

    public Object peek() {
        if (currentPosition + 1 >= allText.size()) {
            System.exit(6);
            return null;
        } else {
            return allText.get(currentPosition + 1);
        }
    }

    public Object peekTwo() {
        if (currentPosition + 2 >= allText.size()) {
            System.exit(7);
            return null;
        } else {
            return allText.get(currentPosition + 2);
        }
    }

    public Object peekThree() {
        if (currentPosition + 3 >= allText.size()) {
            System.exit(8);
            return null;
        } else {
            return allText.get(currentPosition + 3);
        }
    }

    public Object peekBack() {
        if (currentPosition - 1 < 0) {
            System.exit(9);
            return null;
        } else {
            return allText.get(currentPosition - 1);
        }
    }

    public boolean isReserved(String string) {
        for (String reserved : reservedWord) {
            if (string.equals(reserved)) {
                return true;
            }
        }
        return false;
    }

    public boolean isSymbol(String string) {
        for (String symbol : symbols) {
            if (string.equals(symbol)) {
                return true;
            }
        }
        return false;
    }

    public boolean isInExp(Object obj) {
        if (obj instanceof Integer) {
            return true;
        } else {
            for (String string : inExp) {
                if (obj.equals(string)) {
                    return true;
                }
            }
        }
        return this.identifiers.containsKey(obj);
    }

    public boolean isInCondExp(Object obj) {
        if (obj instanceof Integer) {
            return true;
        } else {
            for (String string : inCondExp) {
                if (obj.equals(string)) {
                    return true;
                }
            }
        }
        return this.identifiers.containsKey(obj);
    }

    public boolean isIdent(Object obj) {
        return this.identifiers.containsKey(obj);
    }

    public boolean isConst(Object obj) {
        return this.constIdent.containsKey(obj);
    }

    public boolean isFunction(Object obj) {
        return this.funcIdent.containsKey(obj);
    }

    public Map<String, List<String>> getFuncIdent() {
        return funcIdent;
    }

    public void check() {
        for (int i = currentPosition; !(allText.get(i).equals(",") || allText.get(i).equals(";")); i++) {
            if ((isIdent(allText.get(i)) && !isConst(allText.get(i)))) {
                System.exit(10);
            }
        }
    }


}